#ifndef NETWORK_PROTOCOL_H
#define NETWORK_PROTOCOL_H

#include "../../include/gudb.h"
#include <stdint.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

// MySQL Protocol Constants
#define MYSQL_PROTOCOL_VERSION       10
#define MYSQL_SERVER_VERSION         "5.7.44-GuDB-1.0.0"
#define MYSQL_MAX_PACKET_SIZE        (16 * 1024 * 1024)  // 16MB
#define MYSQL_HEADER_SIZE            4
#define MYSQL_AUTH_PLUGIN_DATA_LEN   20
#define MYSQL_CAPABILITY_FLAGS_SIZE  4

// MySQL Command Types
typedef enum {
    COM_SLEEP               = 0x00,
    COM_QUIT                = 0x01,
    COM_INIT_DB             = 0x02,
    COM_QUERY               = 0x03,
    COM_FIELD_LIST          = 0x04,
    COM_CREATE_DB           = 0x05,
    COM_DROP_DB             = 0x06,
    COM_REFRESH             = 0x07,
    COM_SHUTDOWN            = 0x08,
    COM_STATISTICS          = 0x09,
    COM_PROCESS_INFO        = 0x0a,
    COM_CONNECT             = 0x0b,
    COM_PROCESS_KILL        = 0x0c,
    COM_DEBUG               = 0x0d,
    COM_PING                = 0x0e,
    COM_TIME                = 0x0f,
    COM_DELAYED_INSERT      = 0x10,
    COM_CHANGE_USER         = 0x11,
    COM_BINLOG_DUMP         = 0x12,
    COM_TABLE_DUMP          = 0x13,
    COM_CONNECT_OUT         = 0x14,
    COM_REGISTER_SLAVE      = 0x15,
    COM_STMT_PREPARE        = 0x16,
    COM_STMT_EXECUTE        = 0x17,
    COM_STMT_SEND_LONG_DATA = 0x18,
    COM_STMT_CLOSE          = 0x19,
    COM_STMT_RESET          = 0x1a,
    COM_SET_OPTION          = 0x1b,
    COM_STMT_FETCH          = 0x1c,
    COM_DAEMON              = 0x1d,
    COM_BINLOG_DUMP_GTID    = 0x1e,
    COM_RESET_CONNECTION    = 0x1f
} mysql_command_t;

// MySQL Response Types
typedef enum {
    MYSQL_TYPE_OK           = 0x00,
    MYSQL_TYPE_ERR          = 0xff,
    MYSQL_TYPE_EOF          = 0xfe,
    MYSQL_TYPE_LOCAL_INFILE = 0xfb
} mysql_response_type_t;

// MySQL Field Types
typedef enum {
    MYSQL_TYPE_DECIMAL      = 0x00,
    MYSQL_TYPE_TINY         = 0x01,
    MYSQL_TYPE_SHORT        = 0x02,
    MYSQL_TYPE_LONG         = 0x03,
    MYSQL_TYPE_FLOAT        = 0x04,
    MYSQL_TYPE_DOUBLE       = 0x05,
    MYSQL_TYPE_NULL         = 0x06,
    MYSQL_TYPE_TIMESTAMP    = 0x07,
    MYSQL_TYPE_LONGLONG     = 0x08,
    MYSQL_TYPE_INT24        = 0x09,
    MYSQL_TYPE_DATE         = 0x0a,
    MYSQL_TYPE_TIME         = 0x0b,
    MYSQL_TYPE_DATETIME     = 0x0c,
    MYSQL_TYPE_YEAR         = 0x0d,
    MYSQL_TYPE_NEWDATE      = 0x0e,
    MYSQL_TYPE_VARCHAR      = 0x0f,
    MYSQL_TYPE_BIT          = 0x10,
    MYSQL_TYPE_TIMESTAMP2   = 0x11,
    MYSQL_TYPE_DATETIME2    = 0x12,
    MYSQL_TYPE_TIME2        = 0x13,
    MYSQL_TYPE_JSON         = 0xf5,
    MYSQL_TYPE_NEWDECIMAL   = 0xf6,
    MYSQL_TYPE_ENUM         = 0xf7,
    MYSQL_TYPE_SET          = 0xf8,
    MYSQL_TYPE_TINY_BLOB    = 0xf9,
    MYSQL_TYPE_MEDIUM_BLOB  = 0xfa,
    MYSQL_TYPE_LONG_BLOB    = 0xfb,
    MYSQL_TYPE_BLOB         = 0xfc,
    MYSQL_TYPE_VAR_STRING   = 0xfd,
    MYSQL_TYPE_STRING       = 0xfe,
    MYSQL_TYPE_GEOMETRY     = 0xff
} mysql_field_type_t;

// MySQL Capability Flags
typedef enum {
    CLIENT_LONG_PASSWORD                = 0x00000001,
    CLIENT_FOUND_ROWS                   = 0x00000002,
    CLIENT_LONG_FLAG                    = 0x00000004,
    CLIENT_CONNECT_WITH_DB              = 0x00000008,
    CLIENT_NO_SCHEMA                    = 0x00000010,
    CLIENT_COMPRESS                     = 0x00000020,
    CLIENT_ODBC                         = 0x00000040,
    CLIENT_LOCAL_FILES                  = 0x00000080,
    CLIENT_IGNORE_SPACE                 = 0x00000100,
    CLIENT_PROTOCOL_41                  = 0x00000200,
    CLIENT_INTERACTIVE                  = 0x00000400,
    CLIENT_SSL                          = 0x00000800,
    CLIENT_IGNORE_SIGPIPE               = 0x00001000,
    CLIENT_TRANSACTIONS                 = 0x00002000,
    CLIENT_RESERVED                     = 0x00004000,
    CLIENT_SECURE_CONNECTION            = 0x00008000,
    CLIENT_MULTI_STATEMENTS             = 0x00010000,
    CLIENT_MULTI_RESULTS                = 0x00020000,
    CLIENT_PS_MULTI_RESULTS             = 0x00040000,
    CLIENT_PLUGIN_AUTH                  = 0x00080000,
    CLIENT_CONNECT_ATTRS                = 0x00100000,
    CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000,
    CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = 0x00400000,
    CLIENT_SESSION_TRACK                = 0x00800000,
    CLIENT_DEPRECATE_EOF                = 0x01000000,
    CLIENT_OPTIONAL_RESULTSET_METADATA  = 0x02000000,
    CLIENT_ZSTD_COMPRESSION_ALGORITHM   = 0x04000000,
    CLIENT_QUERY_ATTRIBUTES             = 0x08000000,
    MULTI_FACTOR_AUTHENTICATION         = 0x10000000,
    CLIENT_CAPABILITY_EXTENSION         = 0x20000000,
    CLIENT_SSL_VERIFY_SERVER_CERT       = 0x40000000,
    CLIENT_REMEMBER_OPTIONS             = 0x80000000
} mysql_capability_t;

// MySQL Error Codes
typedef enum {
    ER_HANDSHAKE_ERROR             = 1043,
    ER_DBACCESS_DENIED_ERROR       = 1044,
    ER_ACCESS_DENIED_ERROR         = 1045,
    ER_NO_DB_ERROR                 = 1046,
    ER_UNKNOWN_COM_ERROR           = 1047,
    ER_BAD_HOST_ERROR              = 1130,
    ER_HANDSHAKE_ERROR_TCPIP       = 1129,
    ER_HOST_NOT_PRIVILEGED         = 1130,
    ER_UNKNOWN_ERROR               = 1105,
    ER_SYNTAX_ERROR                = 1064,
    ER_PARSE_ERROR                 = 1064,
    ER_TABLE_EXISTS_ERROR          = 1050,
    ER_BAD_TABLE_ERROR             = 1051
} mysql_error_code_t;

// MySQL Status Flags
typedef enum {
    SERVER_STATUS_IN_TRANS             = 0x0001,
    SERVER_STATUS_AUTOCOMMIT           = 0x0002,
    SERVER_MORE_RESULTS_EXISTS         = 0x0008,  
    SERVER_STATUS_NO_GOOD_INDEX_USED   = 0x0010,
    SERVER_STATUS_NO_INDEX_USED        = 0x0020,
    SERVER_STATUS_CURSOR_EXISTS        = 0x0040,
    SERVER_STATUS_LAST_ROW_SENT        = 0x0080,
    SERVER_STATUS_DB_DROPPED           = 0x0100,
    SERVER_STATUS_NO_BACKSLASH_ESCAPES = 0x0200,
    SERVER_STATUS_METADATA_CHANGED     = 0x0400,
    SERVER_QUERY_WAS_SLOW              = 0x0800,
    SERVER_PS_OUT_PARAMS               = 0x1000,
    SERVER_STATUS_IN_TRANS_READONLY    = 0x2000,
    SERVER_SESSION_STATE_CHANGED       = 0x4000
} mysql_status_flag_t;

// MySQL Packet Structure
typedef struct mysql_packet {
    uint32_t length;        // Packet length (3 bytes)
    uint8_t sequence_id;    // Sequence ID (1 byte)
    uint8_t* payload;       // Packet payload
    size_t payload_size;    // Size of allocated payload buffer
} mysql_packet_t;

// MySQL Handshake Packet
typedef struct mysql_handshake {
    uint8_t protocol_version;
    char server_version[64];
    uint32_t connection_id;
    char auth_plugin_data_part_1[8];
    uint8_t filler;
    uint32_t capability_flags_1;
    uint8_t character_set;
    uint16_t status_flags;
    uint32_t capability_flags_2;
    uint8_t auth_plugin_data_len;
    char reserved[10];
    char auth_plugin_data_part_2[13];
    char auth_plugin_name[64];
} mysql_handshake_t;

// MySQL Handshake Response
typedef struct mysql_handshake_response {
    uint32_t capability_flags;
    uint32_t max_packet_size;
    uint8_t character_set;
    char reserved[23];
    char username[64];
    uint8_t auth_response_len;
    char auth_response[256];
    char database[64];
    char auth_plugin_name[64];
} mysql_handshake_response_t;

// MySQL OK Packet
typedef struct mysql_ok_packet {
    uint8_t header;
    uint64_t affected_rows;
    uint64_t last_insert_id;
    uint16_t status_flags;
    uint16_t warnings;
    char* info;
    char* session_state_changes;
} mysql_ok_packet_t;

// MySQL Error Packet
typedef struct mysql_err_packet {
    uint8_t header;
    uint16_t error_code;
    char sql_state_marker;
    char sql_state[5];
    char* error_message;
} mysql_err_packet_t;

// MySQL Field Definition
typedef struct mysql_field_def {
    char* catalog;
    char* schema;
    char* table;
    char* org_table;
    char* name;
    char* org_name;
    uint64_t length_of_fixed_fields;
    uint16_t character_set;
    uint32_t column_length;
    uint8_t type;
    uint16_t flags;
    uint8_t decimals;
    uint16_t filler;
} mysql_field_def_t;

// MySQL Result Set
typedef struct mysql_result_set {
    uint64_t column_count;
    mysql_field_def_t* fields;
    uint64_t row_count;
    char*** rows;           // Array of row arrays of column strings
    uint64_t* row_lengths;  // Length of each row's columns
} mysql_result_set_t;

// Connection State
typedef enum {
    CONN_STATE_INIT,
    CONN_STATE_HANDSHAKE_SENT,
    CONN_STATE_AUTHENTICATED,
    CONN_STATE_COMMAND_READY,
    CONN_STATE_QUERY_EXECUTING,
    CONN_STATE_RESULT_SENDING,
    CONN_STATE_CLOSING,
    CONN_STATE_CLOSED
} connection_state_t;

// Client Connection
typedef struct mysql_connection {
    int sockfd;
    struct sockaddr_in client_addr;
    connection_state_t state;
    
    // Protocol state
    uint8_t sequence_id;
    uint32_t connection_id;
    uint32_t capability_flags;
    uint8_t character_set;
    uint16_t status_flags;
    
    // Authentication
    char username[64];
    char database[64];
    char auth_plugin_data[MYSQL_AUTH_PLUGIN_DATA_LEN + 1];
    bool authenticated;
    
    // Buffer management
    uint8_t* read_buffer;
    size_t read_buffer_size;
    size_t read_buffer_pos;
    uint8_t* write_buffer;
    size_t write_buffer_size;
    size_t write_buffer_pos;
    
    // Current transaction state
    gudb_txn* current_txn;
    bool in_transaction;
    bool autocommit;
    
    // Server reference
    void* server_ref;  // Reference to network_server_t
    
    // Statistics
    uint64_t queries_executed;
    uint64_t bytes_sent;
    uint64_t bytes_received;
    time_t connect_time;
    time_t last_activity;
    
    // Threading
    pthread_t thread;
    pthread_mutex_t mutex;
    
    // Linked list for connection pool
    struct mysql_connection* next;
    struct mysql_connection* prev;
} mysql_connection_t;

// Network Server
typedef struct network_server {
    int listen_sockfd;
    struct sockaddr_in server_addr;
    uint16_t port;
    bool running;
    
    // Connection management
    mysql_connection_t* connections;
    uint32_t connection_count;
    uint32_t max_connections;
    uint32_t next_connection_id;
    
    // Thread pool
    pthread_t* worker_threads;
    pthread_t accept_thread;
    uint32_t thread_count;
    pthread_mutex_t connection_mutex;
    pthread_cond_t connection_cond;
    
    // Database reference
    gudb* database;
    
    // Server statistics
    uint64_t total_connections;
    uint64_t current_connections;
    uint64_t max_used_connections;
    uint64_t aborted_connects;
    uint64_t aborted_clients;
    
    // Network buffers
    size_t read_buffer_size;
    size_t write_buffer_size;
    
    pthread_mutex_t stats_mutex;
} network_server_t;

// Protocol Functions

// Packet handling
mysql_packet_t* mysql_packet_create(uint32_t length, uint8_t sequence_id);
void mysql_packet_destroy(mysql_packet_t* packet);
int mysql_packet_write_uint8(mysql_packet_t* packet, size_t offset, uint8_t value);
int mysql_packet_write_uint16(mysql_packet_t* packet, size_t offset, uint16_t value);
int mysql_packet_write_uint24(mysql_packet_t* packet, size_t offset, uint32_t value);
int mysql_packet_write_uint32(mysql_packet_t* packet, size_t offset, uint32_t value);
int mysql_packet_write_uint64(mysql_packet_t* packet, size_t offset, uint64_t value);
int mysql_packet_write_string(mysql_packet_t* packet, size_t offset, const char* str);
int mysql_packet_write_lenenc_string(mysql_packet_t* packet, size_t offset, const char* str);
int mysql_packet_write_lenenc_int(mysql_packet_t* packet, size_t offset, uint64_t value);

uint8_t mysql_packet_read_uint8(mysql_packet_t* packet, size_t offset);
uint16_t mysql_packet_read_uint16(mysql_packet_t* packet, size_t offset);
uint32_t mysql_packet_read_uint24(mysql_packet_t* packet, size_t offset);
uint32_t mysql_packet_read_uint32(mysql_packet_t* packet, size_t offset);
uint64_t mysql_packet_read_uint64(mysql_packet_t* packet, size_t offset);
char* mysql_packet_read_string(mysql_packet_t* packet, size_t offset, size_t length);
char* mysql_packet_read_lenenc_string(mysql_packet_t* packet, size_t offset, uint64_t* length);
uint64_t mysql_packet_read_lenenc_int(mysql_packet_t* packet, size_t offset);

// Network I/O
int mysql_send_packet(mysql_connection_t* conn, mysql_packet_t* packet);
mysql_packet_t* mysql_recv_packet(mysql_connection_t* conn);
int mysql_send_handshake(mysql_connection_t* conn);
int mysql_recv_handshake_response(mysql_connection_t* conn, mysql_handshake_response_t* response);
int mysql_send_ok(mysql_connection_t* conn, uint64_t affected_rows, uint64_t last_insert_id);
int mysql_send_error(mysql_connection_t* conn, uint16_t error_code, const char* sql_state, const char* message);
int mysql_send_eof(mysql_connection_t* conn, uint16_t warnings, uint16_t status_flags);

// Query handling
int mysql_handle_query(mysql_connection_t* conn, const char* query);
int mysql_send_result_set(mysql_connection_t* conn, mysql_result_set_t* result);
int mysql_send_field_definitions(mysql_connection_t* conn, mysql_result_set_t* result);
int mysql_send_result_rows(mysql_connection_t* conn, mysql_result_set_t* result);

// Result set management
mysql_result_set_t* mysql_result_set_create(uint64_t column_count);
void mysql_result_set_destroy(mysql_result_set_t* result);
int mysql_result_set_add_field(mysql_result_set_t* result, uint64_t index, const char* name, 
                              mysql_field_type_t type, uint32_t length);
int mysql_result_set_add_row(mysql_result_set_t* result, char** row_data, uint64_t* lengths);

// Authentication
int mysql_authenticate_user(mysql_connection_t* conn, const char* username, 
                           const char* auth_response, const char* database);
int mysql_check_password(const char* username, const char* password_hash, const char* auth_data);
void mysql_generate_auth_data(char* auth_data);
void mysql_scramble_password(const char* password, const char* auth_data, char* result);

// Connection management
mysql_connection_t* mysql_connection_create(int sockfd, struct sockaddr_in* client_addr);
void mysql_connection_destroy(mysql_connection_t* conn);
int mysql_connection_init_buffers(mysql_connection_t* conn, size_t read_size, size_t write_size);
void mysql_connection_cleanup_buffers(mysql_connection_t* conn);
void* mysql_connection_handler(void* arg);

// Server management
network_server_t* network_server_create(uint16_t port, gudb* database);
void network_server_destroy(network_server_t* server);
int network_server_start(network_server_t* server);
int network_server_stop(network_server_t* server);
int network_server_accept_connections(network_server_t* server);
void* network_server_worker_thread(void* arg);
void* network_server_accept_thread(void* arg);

// Command handling
int mysql_handle_command(mysql_connection_t* conn, mysql_command_t command, 
                        const uint8_t* payload, uint32_t length);
int mysql_handle_com_quit(mysql_connection_t* conn);
int mysql_handle_com_init_db(mysql_connection_t* conn, const char* database);
int mysql_handle_com_ping(mysql_connection_t* conn);
int mysql_handle_com_statistics(mysql_connection_t* conn);
int mysql_handle_com_process_info(mysql_connection_t* conn);

// Protocol utilities
size_t mysql_lenenc_int_size(uint64_t value);
size_t mysql_lenenc_string_size(const char* str);
uint32_t mysql_calculate_packet_length(const uint8_t* payload, size_t size);
int mysql_validate_packet(mysql_packet_t* packet);

// Error handling
void mysql_set_error(mysql_connection_t* conn, uint16_t error_code, 
                    const char* sql_state, const char* message);
const char* mysql_get_error_message(uint16_t error_code);
const char* mysql_get_command_name(mysql_command_t command);

// Statistics and monitoring
void network_server_print_stats(network_server_t* server);
void mysql_connection_print_stats(mysql_connection_t* conn);
uint32_t network_server_get_connection_count(network_server_t* server);
double network_server_get_avg_response_time(network_server_t* server);

// Configuration
int network_server_set_max_connections(network_server_t* server, uint32_t max_connections);
int network_server_set_buffer_sizes(network_server_t* server, size_t read_size, size_t write_size);
int network_server_set_thread_count(network_server_t* server, uint32_t thread_count);

#endif // NETWORK_PROTOCOL_H